﻿package com.game.astar{
	import com.wooduan.sj.config.template.SchemaTriggerTemplate;
	import com.wooduan.sj.view.scene.character.CharacterViewMediator;
	
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	public class SearchRoad {
		public static function getRoad(sx:int, sy:int, ex:int, ey:int, wall:MapFloor):Array
		{
			var i:int;
			var ep:Point = new Point(ex , ey);
			var sp:Point = new Point(sx, sy);
			var len:int = Point.distance(ep , sp);
			if(wall != null)
			{
				var k:int;
				var j:int;
				var offsetX:int;
				var offsetY:int;
				var revise:Boolean;
				if(wall.isWall(sp.x,sp.y)) 
				{
					revise = false;
					for(k = 0; k < 20&&!revise; k++)
					{
						for(j = 0; j < 20&&!revise; j++)
						{
							offsetX = k%2==0?(-1*(k/2)*15):(k/2)*15;
							offsetY = j%2==0?(-1*(j/2)*15):(j/2)*15;
							if(!wall.isWall(sp.x + offsetX, sp.y + offsetY))
							{
								sx += offsetX;
								sy += offsetY;
								sp.x += offsetX;
								sp.y += offsetY;
								revise = true;
							}
						}
					}
				}
				
				if(wall.isWall(ep.x,ep.y)) 
				{
					revise = false;
					for(k = 0; k < 20&&!revise; k++)
					{
						for(j = 0; j < 20&&!revise; j++)
						{
							offsetX = k%2==0?(-1*(k/2)*15):(k/2)*15;
							offsetY = j%2==0?(-1*(j/2)*15):(j/2)*15;
							if(!wall.isWall(ep.x + offsetX, ep.y + offsetY))
							{
								ex += offsetX;
								ey += offsetY;
								ep.x += offsetX;
								ep.y += offsetY;
								revise = true;
							}
						}
					}
				}
				if(wall.isWall(sp.x,sp.y) || wall.isWall(ep.x,ep.y))
				{
					return [];
				}
			}
			
			var routeAry:Array = Astar.startSearch(sx, sy, ex, ey, wall);
			if(routeAry){
				return getBestPath(sx, sy, ex, ey, routeAry, wall);
			}
			return [];
		}
		
		public static function getCloseToPoint(startX:int, startY:int, endX:int, endY:int, wall:MapFloor):Array{
			var route:Array = getRoad(startX,startY,endX,endY,wall);
			if(route==null || route.length<=0){
				return route;
			}
			var distance:uint = 70;
			var pE:Point = new Point(route[0][0], route[0][1]);
			var pS:Point = new Point(startX, startY);
			var pDis:uint = Point.distance(pE, pS);
			var point:Point;
			var newRoute:Array;
			if (route.length==1){
				if (pDis < distance){
					return [[startX, startY]];
				} else {
					point = pE.clone();
					point.offset((pS.x - pE.x) * distance / pDis, (pS.y - pE.y) * distance / pDis);
					if(point.x == startX && point.y == startY) {
						return [];
					}
					newRoute = [[point.x, point.y]];
					return newRoute;
				}
			}
			newRoute = []; 
			pE = new Point(endX, endY);
			for each(var item:Array in route) {
				pS = new Point(item[0], item[1]);
				pDis = Point.distance(pE, pS);
				
				if(pDis < distance){
					if(pDis > 0) {
						point = pE.clone();
						point.offset((pS.x-pE.x)*distance/pDis,(pS.y-pE.y)*distance/pDis);
						newRoute.push([point.x,point.y]);
						return newRoute;
					} else {
						if(newRoute.length == 0) {
							return [[endX, endY]];
						}
						var lastPoint:Array = newRoute[newRoute.length-1];
						pS = new Point(lastPoint[0], lastPoint[1]);
						pDis = Point.distance(pE, pS);
						point = pE.clone();
						point.offset((pS.x-pE.x)*distance/pDis,(pS.y-pE.y)*distance/pDis);
						newRoute.push([point.x,point.y]);
						return newRoute;
					}
				} else {
					newRoute.push(item);
				}
			}
			if(newRoute.length > 0) {
				return newRoute;
			}
			return [];
		}
		
		private static function getBestPath(startX:int,startY:int,endX:int,endY:int,aStarPath:Array,wall:MapFloor):Array  {
			var xDistance:int = endX - startX;
			var yDistance:int = endY - startY;
			var distance:int = Math.sqrt(xDistance*xDistance + yDistance*yDistance);
			var i:int;
			var tempX:int,tempY:int;
			var flag:Boolean = false;
			var route:Array = [];
			
			for (i = 1;i < distance;i += 10) {
				tempX = Math.round(startX + i*xDistance/distance);
				tempY = Math.round(startY + i*yDistance/distance);	
				if (wall && wall.isWall(tempX, tempY)) {
					flag = true;	
					break;
				}
			}
			if (!flag) {	
				route.push([endX, endY]);
				return route;
			}
			
			var lastP:Array = [startX, startY];
			var dir:int = -1;
			while(aStarPath.length > 0) {
				var nextP:Array = aStarPath.shift();
				var newDir:int = getDir(lastP[0]-nextP[0], lastP[1]-nextP[1], dir);
				if(newDir != dir && dir != -1) {
					route.push(nextP);
				}
				lastP = nextP;
				dir = newDir;
			}
			route.push([endX, endY]);
			var keyPoint:Array = [route[0]];
			for(i = 0; i < route.length-1;) {
				for(var j:int = route.length-1; j > 0; j--) {
					if(through(route[i], route[j], wall)) {
						i = j;
						break;
					}
					if(j == i + 1) {
						i++;
						break;
					}
				}
				keyPoint.push(route[i]);
			}
			return keyPoint;
		}
		
		public static function getDir( xBy:Number , yBy:Number ,dir:int = 0):int{
//			if(xBy==0 && yBy ==0) return dir;
//			if(xBy>0){
//				if(yBy>0){
//					if(xBy>yBy*2.4){
//						return CharResConstant.DIR_RIGHT;
//					}else if(yBy>xBy*2.4){
//						return CharResConstant.DIR_DOWN;
//					}else
//						return CharResConstant.DIR_RIGHT_DOWN;
//				}else{
//					if(xBy>-yBy*2.4){
//						return CharResConstant.DIR_RIGHT;
//					}else if(-yBy>xBy*2.4){
//						return CharResConstant.DIR_UP;
//					}else
//						return CharResConstant.DIR_RIGHT_UP;
//				}
//			}else{
//				if(yBy>0){
//					if(-xBy>yBy*2.4){
//						return CharResConstant.DIR_LEFT;
//					}else if(yBy>-xBy*2.4){
//						return CharResConstant.DIR_DOWN;
//					}else
//						return CharResConstant.DIR_LEFT_DOWN;
//				}else{
//					if(xBy<yBy*2.4){
//						return CharResConstant.DIR_LEFT;
//					}else if(yBy<xBy*2.4){
//						return CharResConstant.DIR_UP;
//					}else
//						return CharResConstant.DIR_LEFT_UP;
//				}
//			}
			return 1;
		}
		
		private static function through(start:Array, end:Array, wall:MapFloor):Boolean
		{
			var tempX:int,tempY:int;
			var xDistance:int = end[0] - start[0];
			var yDistance:int = end[1] - start[1];
			if(xDistance == 0 && yDistance == 0)
			{
				return true;
			}
			var distance:int = Math.sqrt(xDistance*xDistance + yDistance*yDistance);
			for (var i:int = 1;i < distance;i += 10) {
				tempX = Math.round(start[0] + i*xDistance/distance);
				tempY = Math.round(start[1] + i*yDistance/distance);	
				if (wall && wall.isWall(tempX, tempY)) {
					return false;
				}
			}
			return true;
		}
			
		
		public static function findMapPath(scTrg:Dictionary, sourceId:int, destId:int):Array
		{
//			var n:int = getTimer();
//			var deep:int = 0;
//			var wide:int = 0;
//			var isFind:Boolean = false;
//			var useScList:Array = [];
//			var openScList:Array = [];
//			var nowScId:int = sourceId;
//			useScList[sourceId] = true;
//			openScList[deep] = [{id:sourceId}];
//			while(true)
//			{
//				for each(var trg:SchemaTriggerTemplate in scTrg)
//				{
//					if(!useScList[trg.getArg1()] && trg.getSchemaId() == nowScId)
//					{
//						useScList[trg.getArg1()] = true;
//						if(!openScList[deep])
//						{
//							openScList[deep] = [];
//						}
//						openScList[deep].push({parent:openScList[deep][wide], trigger:trg});
//					}
//					if(nowScId == destId)
//					{
//						isFind = true;
//						break;
//					}
//				}
//				if(isFind)
//				{
//					break;
//				}
//				wide++;
//				if(!openScList[deep][wide])
//				{
//					deep++;
//					wide = 0;
//				}
//				if(!openScList[deep])
//				{
//					break;
//				}
//				nowScId =  openScList[deep][wide].trigger.getArg1();
//			}
//			var path:Array = [];
//			if(isFind)
//			{
//				var lastObj:Object = openScList[deep][wide];
//				while(lastObj.parent)
//				{
//					path.unshift(lastObj.trigger.getId());
//					lastObj = lastObj.parent;
//				}
//			}
//			trace(getTimer()-n);
			return path;
		}
	}
}